import EventHandle from './events'

interface Fmap {
  old: Function,
  now: Function
}

interface EventTypeFuns {
  eventHandle: EventHandle,
  fmaps: Array<Fmap>
}

/**
 * 执行入口函数
 *
 * @export
 * @class Kangaroo
 */
export default class Kangaroo {

  /**
   *
   *
   * @type {*}
   * @memberof Kangaroo
   */
  _knamesapce: any = {}
  _root: Kangaroo = this
  // eventOn: Function = window.addEventListener
  // eventOff: Function = window.removeEventListener
  actEvent = []
  eventHandles = {}
  fmaps = {}
  /**
   * Creates an instance of Kangaroo.
   * @param {Function} eventOn
   * @param {Function} eventOff
   * @memberof Kangaroo
   */
  constructor(
    public eventOn: Function = window.addEventListener,
    public eventOff: Function = window.removeEventListener,
    public eventEnv: any = window
  ) {
    // if (eventOn) this.eventOn = eventOn
    // if (eventOff) this.eventOff = eventOff
  }
  /**
   * 添加window事件
   *
   * @param {string} evenType
   * @param {Function} func
   * @returns {Kangaroo}
   * @memberof Kangaroo
   */
  add(evenType: string, func: Function): Kangaroo {
    const keys = evenType.split(':')
    evenType = keys[0]
    if (!this._root.eventHandles[evenType]) {
      this._root.eventHandles[evenType] = new EventHandle(this._root, evenType)
    }
    this.fmaps[evenType] = this.fmaps[evenType] || []
    const _this = this
    const fmap = (function (keys, func) {
      return {
        old: func,
        now: keys[1] ? function (event: any) {
          func(event)
          if (keys[1] === 'once') _this.destroy(evenType, func)
        } : func
      }
    })(keys, func)
    func = fmap.now
    this.fmaps[evenType].push(fmap)
    this._root.eventHandles[evenType].add(func)
    return this
  }

  /**
   * 触发自定义的window事件
   *
   * @param {string} evenType
   * @param {any} data
   * @returns {Kangaroo}
   * @memberof Kangaroo
   */
  custom(evenType: string, data: any): Kangaroo {
    let customEvent
    if (window['CustomEvent']) {
      customEvent = new CustomEvent(evenType, {
        detail: data
      })
    } else {
      customEvent = document.createEvent('HTMLEvents')
      customEvent.initEvent(evenType, !1, !0)
      customEvent.detail = data
    }
    window.dispatchEvent(customEvent)
    return this
  }

  /**
   * 验证是否需要异常事件方法
   *
   * @param {*} obj
   * @param {*} event
   * @returns {Boolean}
   * @memberof Kangaroo
   */
  test(obj: any, event: any) {
    if (obj) return true
    this.destroyEventHandle(this._root.actEvent[0], this._root.actEvent[1])
    return false
  }

  /**
   * 触发事件(暂无实现)
   * @deprecated
   * @param {string} evenType
   * @param {any} data
   * @returns {Kangaroo}
   * @memberof Kangaroo
   */
  dispatch(evenType: string, data: any): Kangaroo {
    return this
  }

  /**
   * 指定要销毁的事件类
   *
   * @param {string} evenType
   * @param {Function} [func]
   * @memberof Kangaroo
   */
  destroyEventHandle(evenType: string, func?: Function) {
    const eventHandle: EventHandle = this._root.eventHandles[evenType]
    const fmaps = this.fmaps[evenType]
    if (!fmaps || !eventHandle) return
    let destroyFuns = fmaps
    if (func) {
      for (let i = 0; i < fmaps.length; i++) {
        const element = fmaps[i]
        if (element.old === func) {
          destroyFuns = [element]
          fmaps.splice(i, 1)
          break
        }
      }
    }
    eventHandle.destroy(destroyFuns.map(val => val.now))
    if (!this.fmaps[evenType].length || !func) delete this.fmaps[evenType]
  }
  /**
   * 销毁事件
   *
   * @param {string} [evenType]
   * @param {Function} [funs]
   * @returns {Kangaroo}
   * @memberof Kangaroo
   */
  destroy(evenType?: string, funs?: Function): Kangaroo {
    this.destroyNameSpace(evenType, funs)
    if (!evenType) {
      for (const key in this._root.eventHandles) {
        this.destroyEventHandle(key)
      }
      return this
    }
    this.destroyEventHandle(evenType, funs)
    return this
  }
  destroyNameSpace(evenType?: string, funs?: Function) {
    for (const key in this._knamesapce) {
      this.clearNameSpace(key, evenType, funs)
    }
  }
  clearNameSpace(nsp: string, evenType?: string, funs?: Function) {
    const kangaroos = this._knamesapce[nsp]
    if (!kangaroos) return
    this._knamesapce[nsp] = kangaroos.filter(kangaroo => {
      kangaroo.destroy(evenType, funs)
      return Object.keys(kangaroo.fmaps).length
    })
  }
  /**
   * 命名空间区分事件订阅
   *
   * @param {string} nsp
   * @returns {Kangaroo} 
   * @memberof Kangaroo
   */
  namespace(nsp: string): Kangaroo {
    const kangaroo = new Kangaroo()
    kangaroo._root = this._root
    if (!this._knamesapce[nsp]) this._knamesapce[nsp] = []
    this._knamesapce[nsp].push(kangaroo)
    return kangaroo
  }


  /**
   * 
   *
   * @param {Kangaroo} kangaroo
   * @returns {Kangaroo}
   * @memberof Kangaroo
   */
  root(kangaroo: Kangaroo): Kangaroo {
    this._root = kangaroo
    kangaroo.eventHandles = { ...kangaroo.eventHandles, ...this.eventHandles }
    return this
  }
}

